package util

import (
	"reflect"

	"sync/atomic"

	"github.com/cosiner/zerver"
)

type (
	RestApiProxy struct {
		varname  string
		itemtype reflect.Type

		zerver.MapHandler
		store map[string]interface{}
		// resource manager(encoding type)
		defManager IResourceMaster
		mapManager map[string]IResourceMaster // encode(json,gob,...) --> manger
		// access counter
		getCount int64
		setCount int64
		delCount int64
	}
)

const (
	EncodeType = "encode"
)

func NewRestApiProxy(varname string, itemtype reflect.Type, manager IResourceMaster) *RestApiProxy {
	proxy := &RestApiProxy{
		itemtype:   itemtype,
		varname:    varname,
		store:      make(map[string]interface{}),
		MapHandler: make(zerver.MapHandler),
		defManager: manager,
		mapManager: make(map[string]IResourceMaster),
	}
	if proxy.defManager == nil {
		proxy.defManager = zerver.DefaultResourceMaster
	}
	return proxy
}

func (proxy *RestApiProxy) SetResourceManager(encode string, manager IResourceMaster) {
	if len(encode) > 0 {
		proxy.mapManager[encode] = manager
	} else {
		proxy.defManager = manager
	}
}

func (proxy *RestApiProxy) getResourceManager(encode string) (manager IResourceMaster) {
	if len(encode) > 0 {
		manager = proxy.mapManager[encode]
	} else {
		manager = proxy.defManager
	}
	return
}

func (proxy *RestApiProxy) Init(*zerver.Server) error {
	proxy.MapHandler[zerver.GET] = proxy.Get
	proxy.MapHandler[zerver.POST] = proxy.Post
	proxy.MapHandler[zerver.PUT] = proxy.Post
	proxy.MapHandler[zerver.DELETE] = proxy.Delete
	return nil
}

func (proxy *RestApiProxy) GetCounter() (getCnt, setCnt, delCnt int64) {
	getCnt, setCnt, delCnt = atomic.LoadInt64(&proxy.getCount), atomic.LoadInt64(&proxy.setCount), atomic.LoadInt64(&proxy.delCount)
	return
}

// Access Counter
func (proxy *RestApiProxy) Filter(req zerver.Request, reply zerver.Response, chain zerver.FilterChain) {
	switch req.Method() {
	case zerver.GET:
		//atomic.AddInt64(&proxy.getCount, 1)
	case zerver.POST, zerver.PUT:
		//atomic.AddInt64(&proxy.setCount, 1)
	case zerver.DELETE:
		//atomic.AddInt64(&proxy.delCount, 1)
	}
	chain(req, reply)
}

func (proxy *RestApiProxy) Get(req zerver.Request, reply zerver.Response) {
	name := req.URLVar(proxy.varname)
	if len(name) > 0 {
		if val, exist := proxy.store[name]; exist {
			manager := proxy.getResourceManager(req.Param(EncodeType))
			if manager == nil {
				reply.ReportInternalServerError()
			} else if err := manager.Send(reply, "", val); err != nil {
				reply.ReportInternalServerError()
			}
		} else {
			reply.ReportNotFound()
		}
	} else {
		reply.ReportBadRequest()
	}
}

func (proxy *RestApiProxy) Post(req zerver.Request, reply zerver.Response) {
	name := req.URLVar(proxy.varname)
	if len(name) == 0 {
		reply.ReportBadRequest()
		return
	}

	val := reflect.New(proxy.itemtype).Interface()

	manager := proxy.getResourceManager(req.Param(EncodeType))

	if manager == nil {
		reply.ReportInternalServerError()
	} else if err := manager.Recieve(req, val); err == nil {
		proxy.store[name] = val
		reply.ReportOK()
	} else {
		reply.ReportBadRequest()
	}
}

func (proxy *RestApiProxy) Delete(req zerver.Request, reply zerver.Response) {
	name := req.URLVar(proxy.varname)
	if len(name) > 0 {
		delete(proxy.store, name)
		reply.ReportOK()
	} else {
		reply.ReportBadRequest()
	}
}
